package com.thug.engine;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.primitive.Rectangle;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;

import android.content.Context;
import android.util.Log;

import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.thug.entities.Bot;
import com.thug.entities.Gold;
import com.thug.entities.Obstacle;
import com.thug.entities.Wall;
import com.thug.managers.BotManager;
import com.thug.managers.GoldManager;
import com.thug.managers.ObstacleManager;
import com.thug.managers.WallManager;

public class StageLoader {

	public enum FileRegion {
		RGN_TILEDTEXTURE,
		RGN_PLANETEXTURE,
		RGN_SOUND,

		RGN_STAGESETTINGS,
		RGN_BACKGROUND,
		RGN_PLAYERSETTINGS,

		RGN_BOT,
		RGN_WALL,
		RGN_OBSTACLE,
		RGN_GOLD,
		RGN_PATH,
		RGN_REGION,
		RGN_UNKNOWN
	}



	private FileRegion mRegion;
	//private Stack<FileRegion> mFileRegions;
	private final SceneManager mSceneMgr;
	//private final Gameplay mGameplay;
	private EntityManagers mManagers;
	private BufferedReader mReader;
	private WallManager mWallManager;
	private ObstacleManager mObstacleManager;
	private GoldManager mGoldManager;
	private BotManager mBotManager;

	public StageLoader(SceneManager s) {
		mSceneMgr = s;
		mManagers = EntityManagers.getInstance();
		//mGameplay = g;
		//mFileRegions = new Stack<StageLoader.FileRegion>();
		mRegion = FileRegion.RGN_UNKNOWN;
	}

	public void LoadStage(String filename) { 

		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		SoundFactory.setAssetBasePath("mfx/");
		MusicFactory.setAssetBasePath("mfx/");

		Context c = mSceneMgr.getApplicationContext();

		BitmapTextureAtlas mTexture = new BitmapTextureAtlas(512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		TextureRegion mTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mTexture, c, "onscreen_control_knob.png", 0, 0);
		mSceneMgr.getEngine().getTextureManager().loadTexture(mTexture);
		mSceneMgr.addResource("obst", mTextureRegion);
		/*
		 * 
		 */
		try {
			mReader = new BufferedReader(new InputStreamReader(mSceneMgr.getApplicationContext().getAssets().open(filename)));
			String line = mReader.readLine();
			while (line != null) {
				Log.d("Stage Loader : ", line.trim());
				processLine(line);
				line = mReader.readLine();
			}
			if(mRegion != FileRegion.RGN_UNKNOWN) {
				Log.d("Stage Loader : ", "unable to read file properly...");
			}
		} catch (Exception e) {
			Log.d("Stage Loader Error: ", e.toString());
		}



	}

	void processLine(String line) {

		if(line.compareTo("[tiled_textures]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_TILEDTEXTURE;
				Log.d("Stage Loader : ", FileRegion.RGN_TILEDTEXTURE.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_TILEDTEXTURE.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[plane_textures]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_PLANETEXTURE;
				Log.d("Stage Loader : ", FileRegion.RGN_PLANETEXTURE.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_PLANETEXTURE.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[sounds]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_SOUND;
				Log.d("Stage Loader : ", FileRegion.RGN_SOUND.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_SOUND.toString() + " Region ended.");
			}
		}
		
		else if(line.compareTo("[stagesettings]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_STAGESETTINGS;
				Log.d("Stage Loader : ", FileRegion.RGN_STAGESETTINGS.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_STAGESETTINGS.toString() + " Region ended.");
			}
		}
		
		else if(line.compareTo("[backgrounds]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_BACKGROUND;
				Log.d("Stage Loader : ", FileRegion.RGN_BACKGROUND.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_BACKGROUND.toString() + " Region ended.");
			}
		}


		else if(line.compareTo("[walls]") == 0) {
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_WALL;
				mWallManager = new WallManager(mSceneMgr);
				//mGameplay.mEntityManagers.add(mWallManager);
				mManagers.registerEntityManager(mWallManager);
				mSceneMgr.addResource("wall_mgr", mWallManager);
				Log.d("Stage Loader : ", FileRegion.RGN_WALL.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_WALL.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[obstacles]") == 0){
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_OBSTACLE;
				mObstacleManager = new ObstacleManager(mSceneMgr);
				//mGameplay.mEntityManagers.add(mObstacleManager);
				mManagers.registerEntityManager(mObstacleManager);
				mSceneMgr.addResource("obstacle_mgr", mObstacleManager);
				Log.d("Stage Loader : ", FileRegion.RGN_OBSTACLE.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_OBSTACLE.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[golds]") == 0){
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_GOLD;
				mGoldManager = new GoldManager(mSceneMgr);
				//mGameplay.mEntityManagers.add(mGoldManager);
				mManagers.registerEntityManager(mGoldManager);
				mSceneMgr.addResource("gold_mgr", mGoldManager);
				Log.d("Stage Loader : ", FileRegion.RGN_GOLD.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_GOLD.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[paths]") == 0){
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_PATH;
				Log.d("Stage Loader : ", FileRegion.RGN_PATH.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_PATH.toString() + " Region ended.");
			}
		}

		else if(line.compareTo("[bots]") == 0){
			if(mRegion == FileRegion.RGN_UNKNOWN) {
				mRegion = FileRegion.RGN_BOT;
				mBotManager = new BotManager(mSceneMgr);
				//mGameplay.mEntityManagers.add(mBotManager);
				mManagers.registerEntityManager(mBotManager);
				mSceneMgr.addResource("bot_mgr", mBotManager);
				Log.d("Stage Loader : ", FileRegion.RGN_BOT.toString() + " Region started.");
			}else{
				mRegion = FileRegion.RGN_UNKNOWN;
				Log.d("Stage Loader : ", FileRegion.RGN_BOT.toString() + " Region ended.");
			}
		}

		else if(mRegion == FileRegion.RGN_TILEDTEXTURE) {
			createTiledTexture(line);
		}
		else if(mRegion == FileRegion.RGN_PLANETEXTURE) {
			createPlaneTexture(line);
		}
		else if(mRegion == FileRegion.RGN_SOUND) {
			createSound(line);
		}
		else if(mRegion == FileRegion.RGN_STAGESETTINGS) {
			loadStageSettings(line);
		}
		else if(mRegion == FileRegion.RGN_BACKGROUND) {
			createBackground(line);
		}
		else if(mRegion == FileRegion.RGN_WALL) {
			createWall(line);
		}
		else if(mRegion == FileRegion.RGN_OBSTACLE) {
			createObstacle(line);
		}
		else if(mRegion == FileRegion.RGN_GOLD) {
			createGold(line);
		}
		else if(mRegion == FileRegion.RGN_PATH) {
			createPath(line);
		}
		else if(mRegion == FileRegion.RGN_BOT) {
			createBot(line);
		}

	}
	
	private void loadStageSettings(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");
		
		float startX = Float.parseFloat(tok.nextToken());
		float startY = Float.parseFloat(tok.nextToken());
		float endX = Float.parseFloat(tok.nextToken());
		float endY = Float.parseFloat(tok.nextToken());
		
		int cols = Integer.parseInt(tok.nextToken());
		int rows = Integer.parseInt(tok.nextToken());
		
		Log.d("stage loader : ", "settings " + startX + ", " + startY + ", " + endX + ", " + endY + ", " + cols + ", " + rows);
		StageSettings settings = new StageSettings(startX, startY, endX, endY, cols, rows);
		//mGameplay.setStageSettings(settings);
		mSceneMgr.addResource("stage_settings", settings);
	}

	//name, xpos, ypos, width, length, rotation, bodytype, bodyshape, density, elasticity, friction, sensor
	//Plane01, -618.003, 17.0997, 32.0, 26.0, 0.0, 2, 1, 1.0, 0.5, 0.5, false
	private void createWall(String line) {
		String name = "";
		float xpos, ypos, width, height, rotation, density, elasticity, friction;
		int bodytype, bodyshape;
		boolean sensor = false;

		xpos = ypos = width = height = rotation = density = elasticity = friction = bodytype = bodyshape = 0; 
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ", ");

		name = tok.nextToken();
		xpos  = Float.parseFloat(tok.nextToken());
		ypos = Float.parseFloat(tok.nextToken());
		width = Float.parseFloat(tok.nextToken());
		height = Float.parseFloat(tok.nextToken());
		rotation = Float.parseFloat(tok.nextToken());
		bodytype = Integer.parseInt(tok.nextToken());
		bodyshape = Integer.parseInt(tok.nextToken());
		density = Float.parseFloat(tok.nextToken());
		elasticity = Float.parseFloat(tok.nextToken());
		friction = Float.parseFloat(tok.nextToken());
		sensor = Boolean.parseBoolean(tok.nextToken());

		xpos = xpos - (width * 0.5f);
		ypos = ypos - (height * 0.5f);
		Rectangle rect = new Rectangle(xpos, ypos, width, height);
		rect.setRotation(rotation);
		rect.setColor(0, 0, 0);

		Utility.BodyDesc desc = new Utility.BodyDesc(density, elasticity, friction, sensor, bodytype, bodyshape, rect);
		Body body = Utility.createBody(mSceneMgr, desc);

		Wall w = new Wall(rect, body);
		//w.attach(mSceneMgr.getScene());
		body.setUserData(w);
		mWallManager.addEntity(w);
		Log.d("stage loader ", name);

	}

	// name, xpos, ypos, xscale, yscale, rotation, bodytype, bodyshape, density, elasticity, friction, sensor, textureID
		// Circle01, -41.9022, -276.169, 1.0, 1.0, 0.0, 1, 2, 1.0, 0.5, 0.5, false, obst
	private void createObstacle(String line) {

		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");

		/*
		 * start parsing
		 */
		String name = tok.nextToken();

		float xpos  = Float.parseFloat(tok.nextToken());
		float ypos = Float.parseFloat(tok.nextToken());

		float xscale = Float.parseFloat(tok.nextToken());
		float yscale = Float.parseFloat(tok.nextToken());

		float rotation = Float.parseFloat(tok.nextToken());

		int bodytype = Integer.parseInt(tok.nextToken());
		int bodyshape = Integer.parseInt(tok.nextToken());

		float density = Float.parseFloat(tok.nextToken());
		float elasticity = Float.parseFloat(tok.nextToken());
		float friction = Float.parseFloat(tok.nextToken());

		boolean sensor = Boolean.parseBoolean(tok.nextToken());

		String textureID = tok.nextToken();

		TextureRegion tregion = (TextureRegion)mSceneMgr.getResource(textureID);
		tregion = tregion.clone();
		xpos = xpos - (tregion.getWidth() * 0.5f);
		ypos = ypos - (tregion.getHeight() * 0.5f);

		Sprite s = new Sprite(xpos, ypos, tregion);
		s.setScale(xscale, yscale);
		s.setRotation(rotation);

		Utility.BodyDesc desc = new Utility.BodyDesc(density, elasticity, friction, sensor, bodytype, bodyshape, s);
		Body b = Utility.createBody(mSceneMgr, desc);

		Obstacle obstacle = new Obstacle(s, b);
		//obstacle.attach(mSceneMgr.getScene());
		b.setUserData(obstacle);
		mObstacleManager.addEntity(obstacle);

	}

	private void createGold(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");

		/*
		 * start parsing
		 */
		String name = tok.nextToken();

		float xpos  = Float.parseFloat(tok.nextToken());
		float ypos = Float.parseFloat(tok.nextToken());

		float xscale = Float.parseFloat(tok.nextToken());
		float yscale = Float.parseFloat(tok.nextToken());

		float rotation = Float.parseFloat(tok.nextToken());

		int bodytype = Integer.parseInt(tok.nextToken());
		int bodyshape = Integer.parseInt(tok.nextToken());

		float density = Float.parseFloat(tok.nextToken());
		float elasticity = Float.parseFloat(tok.nextToken());
		float friction = Float.parseFloat(tok.nextToken());

		boolean sensor = Boolean.parseBoolean(tok.nextToken());

		String textureID = tok.nextToken();

		TiledTextureRegion tregion = (TiledTextureRegion)mSceneMgr.getResource(textureID);
		tregion = tregion.clone();
		xpos = xpos - (tregion.getWidth() * 0.5f);
		ypos = ypos - (tregion.getHeight() * 0.5f);

		AnimatedSprite s = new AnimatedSprite(xpos, ypos, tregion);
		s.setScale(xscale, yscale);
		s.setRotation(rotation);
		s.animate(100);

		Utility.BodyDesc desc = new Utility.BodyDesc(density, elasticity, friction, sensor, bodytype, bodyshape, s);
		Body b = Utility.createBody(mSceneMgr, desc);

		Gold gold = new Gold(s, b);
		gold.attach(mSceneMgr.getScene());
		b.setUserData(gold);
		mGoldManager.addEntity(gold);
	}

	private void createPath(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer lineSegment = new StringTokenizer(line, "#");
		
		String id = lineSegment.nextToken();
		
		Path path = new Path(lineSegment.countTokens());
		while (lineSegment.hasMoreTokens()) {
			
			StringTokenizer tok = new StringTokenizer(lineSegment.nextToken(), ",");
			
			float x = Float.parseFloat(tok.nextToken());
			float y = Float.parseFloat(tok.nextToken());
			path.to(x, y);
		}
		mSceneMgr.addResource(id, path);
	}

	private void createBot(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");

		/*
		 * start parsing
		 * botAhmed, botblue_region, Line01
		 */
		String name = tok.nextToken();
		String textureRgnID = tok.nextToken();
		String pathID = tok.nextToken();
		float duration = Float.parseFloat(tok.nextToken());
		
		
		
		TiledTextureRegion tRegion = (TiledTextureRegion) mSceneMgr.getResource(textureRgnID);
	    AnimatedSprite s = new AnimatedSprite(0, 0, tRegion.clone());
	    s.setScale(0.7f);
	    
	    Path p = (Path) mSceneMgr.getResource(pathID);
		Path newPath = Utility.addOffsetToPath(p, -s.getBaseWidth() * 0.5f, -s.getBaseHeight() * 0.5f);
		float x = newPath.getCoordinatesX()[0];
		float y = newPath.getCoordinatesY()[0];
	    s.setPosition(x, y);
	    //
	    final FixtureDef def = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, true);
		Body b = PhysicsFactory.createCircleBody(mSceneMgr.getPhysicsWorld(), s, BodyType.KinematicBody, def);
		b.setFixedRotation(true);
		
		Bot bot = new Bot(s, b);
		bot.setPatrolPath(newPath, p.getLength() / duration);
		bot.attach(mSceneMgr.getScene());
		b.setUserData(bot);
		mBotManager.addEntity(bot);
	}

	private void createTiledTexture(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer lineSegment = new StringTokenizer(line, "#");
		StringTokenizer tok = new StringTokenizer(lineSegment.nextToken(), ",");


		int quality = 0, width = 0, height = 0;

		width = Integer.parseInt(tok.nextToken());
		height = Integer.parseInt(tok.nextToken());
		quality = Integer.parseInt(tok.nextToken());

		TextureOptions options = TextureOptions.DEFAULT;
		if (quality == 1) {
			options = TextureOptions.BILINEAR_PREMULTIPLYALPHA;
		} else if (quality == 2) {
			options = TextureOptions.BILINEAR;
		} 

		BitmapTextureAtlas mTexture = new BitmapTextureAtlas(width, height, options);

		while(lineSegment.hasMoreTokens()) {

			tok = new StringTokenizer(lineSegment.nextToken(), ",");

			String id = tok.nextToken();
			String filename = tok.nextToken();
			int x = Integer.parseInt(tok.nextToken());
			int y = Integer.parseInt(tok.nextToken());
			int cols = Integer.parseInt(tok.nextToken());
			int rows = Integer.parseInt(tok.nextToken());

			// load texture
			TiledTextureRegion reg = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, mSceneMgr.getApplicationContext(), filename, x, y, cols, rows);
			mSceneMgr.addResource(id, reg);

			Log.d("StageLoader TextureLoader ", "region " + id + ", " + filename + ", " + x + "," + y + ", " + cols + ", " + rows);

		}
		mSceneMgr.getEngine().getTextureManager().loadTexture(mTexture);
	}

	private void createPlaneTexture(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer lineSegment = new StringTokenizer(line, "#");
		StringTokenizer tok = new StringTokenizer(lineSegment.nextToken(), ",");

		int quality = 0, width = 0, height = 0;

		width = Integer.parseInt(tok.nextToken());
		height = Integer.parseInt(tok.nextToken());
		quality = Integer.parseInt(tok.nextToken());

		TextureOptions options = TextureOptions.DEFAULT;
		if (quality == 1) {
			options = TextureOptions.BILINEAR_PREMULTIPLYALPHA;
		} else if (quality == 2) {
			options = TextureOptions.BILINEAR;
		} 

		BitmapTextureAtlas mTexture = new BitmapTextureAtlas(width, height, options);

		while(lineSegment.hasMoreTokens())  {
			tok = new StringTokenizer(lineSegment.nextToken(), ",");

			String id = tok.nextToken();
			String filename = tok.nextToken();
			int x = Integer.parseInt(tok.nextToken());
			int y = Integer.parseInt(tok.nextToken());

			// load texture
			TextureRegion reg = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mTexture, mSceneMgr.getApplicationContext(), filename, x, y);
			mSceneMgr.addResource(id, reg);

			Log.d("StageLoader TextureLoader ", "region " + id + ", " + filename + ", " + x + "," + y);

		}
		mSceneMgr.getEngine().getTextureManager().loadTexture(mTexture);
	}

	private void createSound(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");

		String id = tok.nextToken();
		String file = tok.nextToken();
		String type = tok.nextToken();

		Log.d("Stage Loader ", id + file + type);
		try {
			if(type.compareTo("sound") == 0) {
				Sound s = SoundFactory.createSoundFromAsset(mSceneMgr.getEngine().getSoundManager(), mSceneMgr.getApplicationContext(), file);
				mSceneMgr.addResource(id, s);
			}else{
				Music m = MusicFactory.createMusicFromAsset(mSceneMgr.getEngine().getMusicManager(), mSceneMgr.getApplicationContext(), file);
				mSceneMgr.addResource(id, m);
			}
		} catch (Exception e) {
			Log.d("Stage Loader Error: ", e.toString());
		} 

	}

	private void createBackground(String line) {
		line = line.replaceAll(" ", "");
		StringTokenizer tok = new StringTokenizer(line, ",");
		
		String name = tok.nextToken();
		float xpos = Float.parseFloat(tok.nextToken());
		float ypos = Float.parseFloat(tok.nextToken());
		String texID = tok.nextToken();
		
		//StageSettings settings = mGameplay.getStageSettings();
		StageSettings settings = (StageSettings) mSceneMgr.getResource("stage_settings"); 
		xpos = xpos + settings.getStartX();
		ypos = ypos + settings.getStartY();
		
		TextureRegion reg = (TextureRegion) mSceneMgr.getResource(texID);
		Sprite s = new Sprite(xpos, ypos, reg);
		mSceneMgr.getScene().attachChild(s);
	}


}
